package uns.fit.gis;

import java.util.Vector;

import javax.microedition.lcdui.Graphics;
import uns.fit.gis.mapdrawer.MapCanvas;
import uns.fit.gis.mapobj.Point;

public class Util {
	// Maximum longitude
	public static final double MAX_LONGITUDE = 106.86045;
	// Maximum latitude
	public static final double MAX_LATITUDE = 11.1573;
	// Minimum longitude
	public static final double MIN_LONGITUDE = 106.36345;
	// Minimum latitude
	public static final double MIN_LATITUDE = 10.60249;
	
	public static final double WIDTH = 0.497;
	public static final double HEIGHT = 0.55481;
	
	public static final int WEIGHT = 65535;
	
	//public static String alphabets = "/0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÁÀẢÃẠĂẮẰẲẴẶÂẤẦẨẪẬÉÈẺẼẸÊẾỀỂỄỆÍÌỈĨỊÓÒỎÕỌÔỐỒỔỖỘƠỚỜỞỠỢÚÙỦŨỤƯỨỪỬỮỰÝỲỶỸỴĐ-.,() ";
	public static String alphabets = "/0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÁÀẢÃẠĂẮẰẲẴẶÂẤẦẨẪẬÉÈẺẼẸÊẾỀỂỄỆÍÌỈĨỊÓÒỎÕỌÔỐỒỔỖỘƠỚỜỞỠỢÚÙỦŨỤƯỨỪỬỮỰÝỲỶỸỴĐ ";

	/*
	 * Constants for config
	 */
        //public static String UPDATE_POSITION_URL = "http://hcmus-gps-locator.appspot.com/location/update";
        public static String UPDATE_POSITION_URL = "http://www.mapvn.com/Service1.asmx/SendCurrentPosition";
        public static String REGISTER_URL = "http://localhost:1234/WebSite1/Service.asmx/Register";
        public static int SERVER_DELAY_TIME = 10000;
        public static int DEVICE_ID = 1;
        public static boolean STREET_NAME_IS_ALONG = true;
        public static boolean UPDATE_POSITION = true;
        public static String STORAGE_FOLDER = "file:///root1/";
    /*
     * End of constants for config
     */
    public static final String STR_SEND_CURR_POS = "Id=0&lat=1&lng=2&speed=3";
    public static final String SOUND_FOLDER = "file://localhost/E:/Test2/sound/";
    public static final String USER_LOCATION_FILE_NAME = "user_location";
    //public static final byte TYPE_USER_LOCATION = 50;
    //public static final byte TYPE_CONSTRUCTION_SITE = 80;
	public static final String TURN_LEFT = "TURN LEFT";
	public static final String TURN_RIGHT = "TURN RIGHT";
	public static final String GO_STRAIGHT = "GO STRAIGHT";
	
	public static final String GPS_TRACK_RECORDSTORE_NAME = "GPSRECORDSTORE";
	public static final String USER_LOCATION_RECORDSTORE_NAME = "ULRECORDSTORE";
	
	public static final String OSM_USERNAME = "nlnngu";
	public static final String OSM_PASSWORD = "0907920312";
	/*
	 * This method is only used for the OLD DRAWING WAY
	 */
	public static Point createPoint(double longitude, double latitude) {
		int x = (int)((longitude - MIN_LONGITUDE) / WIDTH * WEIGHT);
		int y = (int)((-latitude + MIN_LATITUDE) / HEIGHT * WEIGHT);
		Point p = new Point(x, y);
		return p;
	}
	
	/*
	 * Get latitude from planar coordinates
	 */
	public static double getLatitude(int y) {
		return (-y * 1.0 / WEIGHT * HEIGHT + MIN_LATITUDE);
	}
	
	/*
	 * Get longitude from planar coordinates
	 */
	public static double getLongitude(int x) {
		return x * 1.0 / WEIGHT * WIDTH + MIN_LONGITUDE;
	}
	
	/*
	 * Get Character from Index (byte)
	 * For displaying Unicode characters,
	 * this method needs modifying, ex: Ă --> *****
	 */
	public static char decodeCharacter(byte b) {
		int index = b & 0xFF;
		if(index < 0 || index >= alphabets.length())
			return alphabets.charAt(alphabets.length() - 1);
		return alphabets.charAt(index);
	}
	
	/*
	 * This method is used to get Street Name from Index Array (bytes)
	 */
	public static String decodeCharacters(byte[] bytes) {
		if(bytes == null)
			return "";
		StringBuffer buffer = new StringBuffer();
		
		for(int i = 0; i< bytes.length; i++) {
			buffer.append(decodeCharacter(bytes[i]));
		}
		return buffer.toString();
	}
	
	/*
	 * http://answers.google.com/answers/threadview/id/515829.html
	 */
	public static Point corPix(int x0, int y0, int x1, int y1, int x2, int y2,
			int x3, int y3, int x, int y) {
		int SY = 320;
		int SX = 240;
		Point point = intersectLines(((SY - y) * x0 + (y) * x3) / SY, ((SY - y)
				* y0 + y * y3)
				/ SY, ((SY - y) * x1 + (y) * x2) / SY, ((SY - y) * y1 + y * y2)
				/ SY, ((SX - x) * x0 + (x) * x1) / SX, ((SX - x) * y0 + x * y1)
				/ SX, ((SX - x) * x3 + (x) * x2) / SX, ((SX - x) * y3 + x * y2)
				/ SX);

		return point;
	}

	private static int det(int a, int b, int c, int d) {
		return a * d - b * c;
	}

	private static Point intersectLines(int x1, int y1, int x2, int y2, int x3,
			int y3, int x4, int y4) {
		int d = det(x1 - x2, y1 - y2, x3 - x4, y3 - y4);

		if (d == 0)
			d = 1;

		int px = det(det(x1, y1, x2, y2), x1 - x2, det(x3, y3, x4, y4), x3 - x4)
				/ d;
		int py = det(det(x1, y1, x2, y2), y1 - y2, det(x3, y3, x4, y4), y3 - y4)
				/ d;
		return new Point(px, py);
	}
	
	public static double calculateDistancePoint2Line(int x0, int y0, int x1, int y1, int x2, int y2) {
		return calculateTriangleArea(x0, y0, x1, y1, x2, y2) / calculateDistancePoint2Point(x1, y1, x2, y2);
	}
	
	public static double calculateTriangleArea(int x0, int y0, int x1, int y1, int x2, int y2) {
		return Math.abs((x2 - x0) * (y1 - y0) - (x1 - x0) * (y2 - y0)) / 2;
	}
	
	public static double calculateDistancePoint2Point(int x0, int y0, int x1, int y1) {
		return Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
	}
	
	public static boolean isInside(int x, int y, int minX, int minY, int maxX, int maxY) {
		if(x > minX && x < maxX &&
				y > minY && y < maxY) {
			return true;
		}
		return false;
	}
	
	public static boolean isInsideLine(int x, int y, int x0, int y0, int x1, int y1) {
		if((x > x0 && x < x1) /*||
				y > y0 && y < y1*/) {
			return true;
		}
		return false;
	}
	
	public static Point getProjectionPoint2Line(int x0, int y0, int x1, int y1, int x2, int y2) {
		//http://www.ltcconline.net/greenl/courses/107/Vectors/DOTCROS.HTM
		//System.out.println("0 = " + x0 + " " + y0);
        //System.out.println("1 = " + x1 + " " + y1);
        //System.out.println("2 = " + x2 + " " + y2);
        
		int x, y;
		
		int u1 = x0 - x1;
        int u2 = y0 - y1;
        int v1 = x2 - x1;
        int v2 = y2 - y1;

        //System.out.println("U = " + u1 + " " + u2);
        //System.out.println("V = " + v1 + " " + v2);
        
        int uv = dot(u1, u2, v1, v2);
        int vv = dot(v1, v2, v1, v2);
        
        //System.out.println("UV = " + uv);
        //System.out.println("VV = " + vv);

        if (vv == 0)
        {
            x = x1;
            y = y1;
        }
        else
        {
            x = uv*v1/vv;
            y = uv*v2/vv;
            x += x1;
            y += y1;
            
            //System.out.println("X = " + x);
            //System.out.println("Y = " + y);

           if(y1 < y2)
           {
               if(y < y1)
               {
                   x = x1;
                   y = y1;
               }
               else if(y > y2)
               {
                   x = x2;
                   y = y2;
               }
           }
           else
           {
               if(y < y2)
               {
                   x = x2;
                   y = y2;
               }
               else if(y > y1)
               {
                   x = x1;
                   y = y1;
               }
           }
        }
		
		return new Point(x, y);
	}
	
	//Compute the dot product AB . BC
    public static int dot(Point A, Point B, Point C){
        int[] AB = new int[2];
        int[] BC = new int[2];
        AB[0] = B.getX() - A.getX();
        AB[1] = B.getY() - A.getY();
        BC[0] = C.getX() - B.getX();
        BC[1] = C.getY() - B.getY();
        int dot = AB[0] * BC[0] + AB[1] * BC[1];
        return dot;
    }
    //Compute the cross product AB x AC
    private static int cross(Point A, Point B, Point C){
        int[] AB = new int[2];
        int[] AC = new int[2];
        AB[0] = B.getX() - A.getX();
        AB[1] = B.getY() - A.getY();
        AC[0] = C.getX() - A.getX();
        AC[1] = C.getY() - A.getY();
        int cross = AB[0] * AC[1] - AB[1] * AC[0];
        return cross;
    }
    //Compute the distance from A to B
    private static double distance(Point A, Point B){
        int d1 = A.getX() - B.getX();
        int d2 = A.getY() - B.getY();
        return Math.sqrt(d1*d1+d2*d2);
    }
    //Compute the distance from AB to C
    //if isSegment is true, AB is a segment, not a line.
    public static double linePointDist(Point A, Point B, Point C, boolean isSegment){
        double dist = cross(A,B,C) / distance(A,B);
        if(isSegment){
            int dot1 = dot(A,B,C);
            if(dot1 > 0)return distance(B,C);
            int dot2 = dot(B,A,C);
            if(dot2 > 0)return distance(A,C);
        }
        return Math.abs(dist);
    } 
    
    public static int dot(int x0, int y0, int x1, int y1) {
    	return (x0*x1) + (y0*y1);
    }
    
	
	public static void drawText(Graphics g, String sText, int x, int y, int fTextColor, int fBorderColor) {
		/*
	    if (fBorderColor >= 0) {
	    	g.setColor(fBorderColor);
	    	g.drawString(sText, x + 1, y, Graphics.TOP | Graphics.LEFT);
	        g.drawString(sText, x - 1, y, Graphics.TOP | Graphics.LEFT);
	        g.drawString(sText, x, y + 1, Graphics.TOP | Graphics.LEFT);
	        g.drawString(sText, x, y - 1, Graphics.TOP | Graphics.LEFT);
	    }
	    g.setColor(fTextColor);
	    g.drawString(sText, x, y, Graphics.TOP | Graphics.LEFT);
	    */
		g.drawString(sText, x, y, Graphics.BOTTOM | Graphics.LEFT);
	}
	
	/*
	 * Tim segment co giao voi man hinh gan diem hien tai nhat
	 */
	public static int findClosestSegment(int x, int y) {
		int closestId = -1;
		int minDistance = Integer.MAX_VALUE;
		
		for(int i = 0; i < MapCanvas.segments.length; i ++) {
			int maxX = MapCanvas.segments[i].getMaxX();
			int maxY = MapCanvas.segments[i].getMaxY();
			int minX = MapCanvas.segments[i].getMinX();
			int minY = MapCanvas.segments[i].getMinY();
			/*
			 * Khuyet diem: chi tim nhung segment ma MBR giao voi man hinh.
			 * Co the ton tai segment khong thoa dieu kien nay
			 * nhung gan diem hien tai hon.
			 */
			if(isIntersecting(minX, minY, maxX, maxY)) {
				for(int j = 0; j < MapCanvas.segments[i].getNumberOfPoints() - 1; j ++) {
					int d = (int)Util.linePointDist(new Point(MapCanvas.segments[i].getX(j), MapCanvas.segments[i].getY(j)), new Point(MapCanvas.segments[i].getX(j + 1), MapCanvas.segments[i].getY(j + 1)), new Point(x, y), true);
					if(minDistance > d) {
						minDistance = d;
						closestId = i;
					}
				}
			}
		}
		
		return closestId;
	}
	
	/*
	 * Reference: http://silentmatt.com/computers/playground/intersection.php
	 */
	public static boolean isIntersecting(int minX, int minY, int maxX, int maxY) {
		//return ((MapCanvas.MinX < maxX) && (MapCanvas.MaxX > minX) && (MapCanvas.MinY < maxY) && (MapCanvas.MaxY > minY));
		int MinX = MapCanvas.MinX - 100;
		int MinY = MapCanvas.MinY - 100;
		int MaxX = MapCanvas.MaxX + 100;
		int MaxY = MapCanvas.MaxY + 100;
		return ((MinX < maxX) && (MaxX > minX) && (MinY < maxY) && (MaxY > minY));
	}
	
	/*
	 * Tim segment nam trong hinh vuong quanh diem hien tai ma gan diem hien tai nhat
	 */
	public static int findClosestSegment2(int x, int y) {
		int closestId = -1;
		int minDistance = Integer.MAX_VALUE;
		
		int minX0 = x - 150;
		int minY0 = y - 150;
		int maxX0 = x + 150;
		int maxY0 = y + 150;
		
		boolean found = false;
		while(!found) {
			for(int i = 0; i < MapCanvas.segments.length; i ++) {
				int maxX = MapCanvas.segments[i].getMaxX();
				int maxY = MapCanvas.segments[i].getMaxY();
				int minX = MapCanvas.segments[i].getMinX();
				int minY = MapCanvas.segments[i].getMinY();
				
				if(isIntersecting(minX0, minY0, maxX0, maxY0, minX, minY, maxX, maxY)) {
					found = true;
					for(int j = 0; j < MapCanvas.segments[i].getNumberOfPoints() - 1; j ++) {
						int d = (int)Util.linePointDist(new Point(MapCanvas.segments[i].getX(j), MapCanvas.segments[i].getY(j)), new Point(MapCanvas.segments[i].getX(j + 1), MapCanvas.segments[i].getY(j + 1)), new Point(x, y), true);
						if(minDistance > d) {
							minDistance = d;
							closestId = i;
						}
					}
				}
			}
			minX0 -= 100;
			minY0 -= 100;
			maxX0 += 100;
			maxY0 += 100;
		}
		return closestId;
	}
	
	public static boolean isIntersecting(int minX0, int minY0, int maxX0, int maxY0, int minX1, int minY1, int maxX1, int maxY1) {
		return ((minX0 < maxX1) && (maxX0 > minX1) && (minY0 < maxY1) && (maxY0 > minY1));
	}
	
	public static boolean contains(int[] array, int element) {
		if(array == null)
			return false;
		
		for(int i = 0; i < array.length; i ++) {
			if(array[i] == element)
				return true;
		}
		return false;
	}
	
	public static void centerScreen(int x, int y) {
		int d = MapCanvas.MaxX - MapCanvas.MinX;
		
		MapCanvas.MinX = x - d / 2;
		MapCanvas.MinY = y - d / 2;
		MapCanvas.MaxX = x + d / 2;
		MapCanvas.MaxY = y + d / 2;
		if(MapCanvas.MinX < 0) {
			MapCanvas.MinX = 0;
			MapCanvas.MaxX = d;
		}
		if(MapCanvas.MinY < 0) {
			MapCanvas.MinY = 0;
			MapCanvas.MaxY = d;
		}
		if(MapCanvas.MaxX > MapCanvas.MAX_X) {
			MapCanvas.MaxX = MapCanvas.MAX_X;
			MapCanvas.MinX = MapCanvas.MAX_X - d;
		}
		if(MapCanvas.MaxY > MapCanvas.MAX_Y) {
			MapCanvas.MaxY = MapCanvas.MAX_Y;
			MapCanvas.MinY = MapCanvas.MAX_Y - d;
		}
	}
	
	//http://softsurfer.com/Archive/algorithm_0101/algorithm_0101.htm
	public static String getTurningDirection(int x0, int y0, int x1, int y1, int x2, int y2) {
        int a = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0);
        if (a > 0)
        {
            return Util.TURN_RIGHT;
        }
        if (a < 0)
        {
        	return Util.TURN_LEFT;
        }
        return Util.GO_STRAIGHT;
    }
	
	//http://discussion.forum.nokia.com/forum/showthread.php?t=97769
	public static String[] split(String original, String separator) {
		Vector nodes = new Vector();
		// Parse nodes into vector
		int index = original.indexOf(separator);
		while (index >= 0) {
			nodes.addElement(original.substring(0, index));
			original = original.substring(index + separator.length());
			index = original.indexOf(separator);
		}
		// Get the last node
		nodes.addElement(original);

		// Create splitted string array
		String[] result = new String[nodes.size()];
		if (nodes.size() > 0) {
			for (int loop = 0; loop < nodes.size(); loop++) {
				result[loop] = (String) nodes.elementAt(loop);
				//System.out.println(result[loop]);
			}

		}

		return result;
	}
	
	//http://forums.sun.com/thread.jspa?threadID=721672
	public static String[] split2(String str, String c) //split string function
    {
        int lenght = str.length();
        int first = 0;
        int last = 0;
        int count = 0;
        for(int i = 0;i < lenght;i++)
        {
          if (str.substring(i,i+1) == c)
          {
            count ++;    
          }
        }
        String[] array = new String[count + 1];
        for (int i = 0;i < lenght;i++)
        {
            if (str.substring(i,i+1) == c)
            {
                last = i;
                array[i] = str.substring(first,last);
                first = last;
            }   
        }
        return array;
    }

        public static String getIMEI() {
            String imei = System.getProperty("phone.imei");
            
            if(imei == null)
                imei = System.getProperty("phone.nokia.IMEI");
            if(imei == null)
                imei = System.getProperty("com.sonyericsson.imei");
            if(imei == null)
                imei = System.getProperty("IMEI");
            if(imei == null)
                imei = System.getProperty("com.motorola.IMEI");
            if(imei == null)
                imei = System.getProperty("com.samsung.imei");
            if(imei == null)
                imei = System.getProperty("com.siemens.imei");
            if(imei == null)
                imei = "0123456789";
            return imei;
        }
        

    	public static byte encodeCharacter(char c) {
    		//String alphabets = "/0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÁÀẢÃẠĂẮẰẲẴẶÂẤẦẨẪẬÉÈẺẼẸÊẾỀỂỄỆÍÌỈĨỊÓÒỎÕỌÔỐỒỔỖỘƠỚỜỞỠỢÚÙỦŨỤƯỨỪỬỮỰÝỲỶỸỴĐ ";
    		//if(alphabets.indexOf(c) > 255)
    		//	System.out.println(alphabets.indexOf(c));
    		if(alphabets.indexOf(c) == -1)
    			c = ' ';
    		return (byte)alphabets.indexOf(c);
    	}
    	
    	public static byte[] encodeStringToBytes(String str) {
    		str = str.toUpperCase();
    		byte[] bytes = new byte[str.length()];
    		for(int i = 0; i < str.length(); i++) {
    			bytes[i] = encodeCharacter(str.charAt(i));
    		}
    		return bytes;
    	}
}
